package com.guigu.gulicommon.config;

import com.guigu.gulicommon.entity.pojo.res.Res;
import com.guigu.gulicommon.exception.BaseException;
import lombok.extern.log4j.Log4j2;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;

import static com.guigu.gulicommon.constant.enumes.res.OtherResCode.PARAMETER_TYPE_ERROR;


/**
 * 公共异常处理类
 * @author 陈俊杰
 */

@ControllerAdvice
@ResponseBody
@Log4j2
public class ExceptionHandlerConfig {

    /**
     * 处理自定义异常
     *
     * @param e 异常信息
     * @return
     */
    @ExceptionHandler(BaseException.class)  //指定该方法要处理的异常类型。
    @ResponseBody
    public Res<String> error(BaseException e) {
        //将异常信息返回给页面展示
        return new Res<>(e.getCode(), e.getMessage());
    }

//    @ExceptionHandler(RedisConnectionException.class)  //指定该方法要处理的异常类型。
//    @ResponseBody
//    public Res<String> error(RedisConnectionException e) {
//        log.error("Redisson远程连接可能超时:\r\n", e);
//        return new Res<>();  //将异常信息返回给页面展示
//    }


    /**
     * 参数校验异常处理
     *
     * @param ex 异常信息
     * @return
     */
    @ExceptionHandler({BindException.class, ConstraintViolationException.class})
    public Res<String> handler(Exception ex) {

        //如果错误消息包含'Failed to convert property value of type'则提示给用户'请输入合法的字段'
        if (ex.getMessage().contains("Failed to convert property value of type")) {
            return new Res<>(PARAMETER_TYPE_ERROR);
        }

        StringBuilder msg = new StringBuilder();
        if (ex instanceof ConstraintViolationException) {
            //单个字段校验
            ConstraintViolationException ce = (ConstraintViolationException) ex;
            ConstraintViolation<?> next = ce.getConstraintViolations().iterator().next();
            msg = new StringBuilder(next.getMessage());
        } else if (ex instanceof BindException) {
            //多个字段校验
            BindException be = (BindException) ex;
            List<FieldError> fieldErrors = be.getBindingResult().getFieldErrors();
            int LINE_WIDTH = 20; // 假设每行最大宽度为20个字符
            int currentLineLength = 0; // 当前行的当前长度
            // 遍历拼接错误信息
            for (int i = 0; i < fieldErrors.size(); i++) {

                FieldError error = fieldErrors.get(i);
                String errorMessage = error.getDefaultMessage();
                int errorLength = 0;
                if (errorMessage != null) {
                    errorLength = errorMessage.length();
                }

                // 计算加上错误信息后的行总长度
                int newLineLength = currentLineLength + errorLength + 3; // 加上"."和"\n"的长度

                // 如果加上新的错误信息后超过行宽，则先换行
                if (newLineLength > LINE_WIDTH) {
//                    msg.append("\r\n");
                    currentLineLength = 0;
                }

                // 添加错误信息
                msg.append((i + 1)).append(". ").append(errorMessage);

                // 更新当前行长度
                currentLineLength += errorLength + 3; // 加上"."和空格的长度

                // 在每个错误信息后添加换行符，除了最后一个
                if (i < fieldErrors.size() - 1) {
                    msg.append("\r\n");
                    currentLineLength = 0; // 下一行开始时重置行长度
                }
            }
        }
        return new Res<>(400, "参数错误,原因如下:" + msg);
    }

    /**
     * 处理非自定义异常
     *
     * @param e 异常信息
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Res<String> error(Exception e) {
        log.error("服务器出现未定义的异常:\r\n", e);
        return Res.error();
    }
}

